package pe.edu.upc.e41a.javasoft.daoImpl;

import java.util.List;
import java.util.Set;

import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;
import javax.persistence.TypedQuery;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.stereotype.Repository;
import org.springframework.transaction.annotation.Transactional;

import pe.edu.upc.e41a.javasoft.dao.TipoDocumentoDao;
import pe.edu.upc.e41a.javasoft.domain.TipoDocumento;
import pe.edu.upc.e41a.javasoft.domain.TipoPersona;
import pe.edu.upc.e41a.javasoft.domain.Usuario;

@Repository(value = "TipoDocumentoDao")
public class TipoDocumentoDaoImpl implements TipoDocumentoDao {

	private static final Log log = LogFactory.getLog(AvisoDaoImpl.class);

	@PersistenceContext
	transient EntityManager em;

	public final EntityManager entityManager() {
		EntityManager entityManager = em;
		if (entityManager == null)
			throw new IllegalStateException(
					"Entity manager has not been injected (is the Spring Aspects JAR configured as an AJC/AJDT aspects library?)");
		return entityManager;

	}
	

	//Métodos persistentes
	@Transactional
	@Override
	public void saveTipoDocumento(TipoDocumento tipoDocumento) {
		if (em == null)
			this.em = this.em;
		em.persist(tipoDocumento);
	}

	@Transactional
	@Override
	public void updateTipoDocumento(TipoDocumento tipoDocumento) {
		if (em == null)
			this.em = this.em;
		em.merge(tipoDocumento);
		em.flush();
	}

	@Transactional
	@Override
	public void deleteTipoDocumento(TipoDocumento tipoDocumento) {
		if (em == null)
			this.em = this.em;
		if (em.contains(tipoDocumento)) {
			em.remove(tipoDocumento);
		} else {
			TipoDocumento attached = this.findTipoDocumento(tipoDocumento.getCodigo());
			em.remove(attached);
		}
	}

	
	// Finders comunes
	@Override
	public long countTipoDocumentoes() {
		return em.createQuery("SELECT COUNT(o) FROM TipoDocumento o",
				Long.class).getSingleResult();
	}

	@Override
	public List<TipoDocumento> findAllTipoDocumentoes() {
		return em.createQuery("SELECT o FROM TipoDocumento o",
				TipoDocumento.class).getResultList();
	}

	@Override
	public TipoDocumento findTipoDocumento(Integer codigo) {
		if (codigo == null)
			return null;
		return em.find(TipoDocumento.class, codigo);
	}

	@Override
	public List<TipoDocumento> findTipoDocumentoEntries(int firstResult,
			int maxResults) {
		return em
				.createQuery("SELECT o FROM TipoDocumento o",
						TipoDocumento.class).setFirstResult(firstResult)
				.setMaxResults(maxResults).getResultList();
	}

	// Finders avanzados
	@Override
	public TypedQuery<TipoDocumento> findTipoDocumentoesByDescripcionEquals(
			String descripcion) {
		if (descripcion == null || descripcion.length() == 0)
			throw new IllegalArgumentException(
					"The descripcion argument is required");

		TypedQuery<TipoDocumento> q = em
				.createQuery(
						"SELECT o FROM TipoDocumento AS o WHERE o.descripcion = :descripcion",
						TipoDocumento.class);
		q.setParameter("descripcion", descripcion);
		return q;
	}

	@Override
	public TypedQuery<TipoDocumento> findTipoDocumentoesByDescripcionIsNotNull() {

		TypedQuery<TipoDocumento> q = em
				.createQuery(
						"SELECT o FROM TipoDocumento AS o WHERE o.descripcion IS NOT NULL",
						TipoDocumento.class);
		return q;
	}

	@Override
	public TypedQuery<TipoDocumento> findTipoDocumentoesByDescripcionIsNull() {

		TypedQuery<TipoDocumento> q = em.createQuery(
				"SELECT o FROM TipoDocumento AS o WHERE o.descripcion IS NULL",
				TipoDocumento.class);
		return q;
	}

	@Override
	public TypedQuery<TipoDocumento> findTipoDocumentoesByDescripcionLike(
			String descripcion) {
		if (descripcion == null || descripcion.length() == 0)
			throw new IllegalArgumentException(
					"The descripcion argument is required");
		descripcion = descripcion.replace('*', '%');
		if (descripcion.charAt(0) != '%') {
			descripcion = "%" + descripcion;
		}
		if (descripcion.charAt(descripcion.length() - 1) != '%') {
			descripcion = descripcion + "%";
		}

		TypedQuery<TipoDocumento> q = em
				.createQuery(
						"SELECT o FROM TipoDocumento AS o WHERE LOWER(o.descripcion) LIKE LOWER(:descripcion)",
						TipoDocumento.class);
		q.setParameter("descripcion", descripcion);
		return q;
	}

	@Override
	public TypedQuery<TipoDocumento> findTipoDocumentoesByDescripcionNotEquals(
			String descripcion) {
		if (descripcion == null || descripcion.length() == 0)
			throw new IllegalArgumentException(
					"The descripcion argument is required");

		TypedQuery<TipoDocumento> q = em
				.createQuery(
						"SELECT o FROM TipoDocumento AS o WHERE o.descripcion != :descripcion",
						TipoDocumento.class);
		q.setParameter("descripcion", descripcion);
		return q;
	}

	@Override
	public TypedQuery<TipoDocumento> findTipoDocumentoesByUsuarios(
			Set<Usuario> usuarios) {
		if (usuarios == null)
			throw new IllegalArgumentException(
					"The usuarios argument is required");

		StringBuilder queryBuilder = new StringBuilder(
				"SELECT o FROM TipoDocumento AS o WHERE");
		for (int i = 0; i < usuarios.size(); i++) {
			if (i > 0)
				queryBuilder.append(" AND");
			queryBuilder.append(" :usuarios_item").append(i)
					.append(" MEMBER OF o.usuarios");
		}
		TypedQuery<TipoDocumento> q = em.createQuery(queryBuilder.toString(),
				TipoDocumento.class);
		int usuariosIndex = 0;
		for (Usuario _usuario : usuarios) {
			q.setParameter("usuarios_item" + usuariosIndex++, _usuario);
		}
		return q;
	}

}
